import 'package:flutter/material.dart';
import '../model/pen/pen.dart';
import '../model/pen/pen_style.dart';

typedef ScrawlShouldDrawCallback = void Function();
typedef ScrawlDrawBeginCallback = void Function();
typedef ScrawlDrawEndCallback = void Function();
typedef ScrawlDrawStateChangeCallback = void Function();

class ScrawlDrawController {
  /// 需要执行刷新逻辑
  final List<ScrawlShouldDrawCallback> shouldDrawCallbacks = [];
  final List<ScrawlDrawBeginCallback> drawBeginCallbacks = [];
  final List<ScrawlDrawEndCallback> drawEndCallbacks = [];
  final List<ScrawlDrawStateChangeCallback> stateChangeCallbacks = [];

  bool _enableTouch = true;
  bool get enableTouch => _enableTouch;
  set enableTouch(bool enableTouch) {
    _enableTouch = enableTouch;
    shouldDrawCallbacks.forEach((callback) => callback?.call());
  }

  /// 当前画笔配置属性
  PenStyle _scrawlPenConfig;

  PenStyle get penStyle => _scrawlPenConfig;
  set penStyle(PenStyle scrawlPenConfig) {
    _scrawlPenConfig = scrawlPenConfig;
    if (scrawlPenConfig is PenStyle) {
      useEraser = false;
    }
  }

  // bool _useEraser = false;
  // bool get useEraser => _useEraser;
  // set useEraser(bool useEraser) {
  //   _useEraser = useEraser;
  // }
  bool useEraser = false;

  /// 当前绘制的画笔
  BasePen _drawingPen;

  List<BasePen> _penHistory = [];
  int _penHistoryIndex = 0;

  /// 添加历史记录
  void pushPen(BasePen pen) {
    if (_penHistory.length > _penHistoryIndex) {
      _penHistory.removeRange(_penHistoryIndex, _penHistory.length);
    }
    _penHistory.add(pen);
    _penHistoryIndex = _penHistory.length;
  }

  /// 撤销历史记录
  void undoPen() {
    _penHistoryIndex -= 1;
    _penHistoryIndex = _penHistoryIndex.clamp(0, _penHistory.length);
  }

  /// 重做历史记录
  void redoPen() {
    _penHistoryIndex += 1;
    _penHistoryIndex = _penHistoryIndex.clamp(0, _penHistory.length);
  }

  bool get canUndo => _penHistoryIndex > 0;
  bool get canRedo => _penHistoryIndex < _penHistory.length;

  /// 清理历史记录
  void clearPenHistory() {
    // _penHistory.clear();
    _penHistoryIndex = 0;
  }

  /// 遍历历史记录
  void penHistoryForEach(void Function(BasePen pen, int index) itemHandler) {
    for (int i = 0; i < _penHistoryIndex; i++) {
      BasePen pen = _penHistory[i];
      itemHandler?.call(pen, i);
    }
  }

  Offset _touchPoint;
  Offset get touchPoint => _touchPoint;
  set touchPoint(Offset touchPoint) {
    _touchPoint = touchPoint;
    shouldDrawCallbacks.forEach((callback) => callback?.call());
  }

  String currenPenId;
  void onDown(Offset touchPoint) {
    if (penStyle.lineWidth == null &&
        penStyle.strokeLineWidth == null &&
        penStyle.imageWidth == null) {
      return;
    }
    if (penStyle.lineWidth <= 0 &&
        penStyle.strokeLineWidth <= 0 &&
        penStyle.imageWidth <= 0) {
      return;
    }

    final style = penStyle.copyWith();
    if (useEraser) {
      _drawingPen = EraserPen(brushId: currenPenId, style: style);
    } else {
      _drawingPen = ScrawlPen(brushId: currenPenId, style: style);
    }

    if (_drawingPen.downEvent(touchPoint)) {
      pushPen(_drawingPen);
      this.touchPoint = touchPoint;
      drawBeginCallbacks.forEach((callback) => callback?.call());
    }
  }

  void onMove(Offset touchPoint) {
    if (_drawingPen == null) {
      return;
    }
    if (_drawingPen.moveEvent(touchPoint)) {
      this.touchPoint = touchPoint;
    }
  }

  void onUp(Offset touchPoint) {
    if (_drawingPen == null) {
      return;
    }
    if (_drawingPen.upEvent(touchPoint)) {
      this.touchPoint = null;
    }
    _drawingPen = null;
    drawEndCallbacks.forEach((callback) => callback?.call());
  }

  List<String> getDrawPensType() {
    List<String> penTypes = [];
    penHistoryForEach((pen, index) {
      String brushId = pen?.getBrushId();
      if (!penTypes.contains(brushId)) {
        penTypes.add(pen?.getBrushId());
      }
    });
    return penTypes;
  }

  int getPensListLength() {
    return _penHistoryIndex;
  }

  /// 清空当前全部数据和缓存
  void clear() {
    _drawingPen = null;
    clearPenHistory();
    shouldDrawCallbacks.forEach((callback) => callback?.call());
    stateChangeCallbacks.forEach((callback) => callback?.call());
  }

  void undo() {
    if (!canUndo) return;
    undoPen();
    shouldDrawCallbacks.forEach((callback) => callback?.call());
    stateChangeCallbacks.forEach((callback) => callback?.call());
  }

  void redo() {
    if (!canRedo) return;
    redoPen();
    shouldDrawCallbacks.forEach((callback) => callback?.call());
    stateChangeCallbacks.forEach((callback) => callback?.call());
  }

  void dispose() {
    shouldDrawCallbacks.clear();
    drawBeginCallbacks.clear();
    drawEndCallbacks.clear();
    stateChangeCallbacks.clear();
  }
}
